﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Network;
using System.Net;
using System.IO;

namespace OnlineGame
{
    class Program
    {
        private static ClientManager Client;
        private static Player Character;
        private static int Players;
        private static List<Player> Opponents;
        private static PacketWriter PktWriter;
        private static PacketReader PktReader;

        private static void Main(string[] args)
        {
            Console.WriteLine("Welcome to the Game.");
            Players = 0;
            Opponents = new List<Player>();
            Thread thrdInput = new Thread(new ThreadStart(InputManager));
            thrdInput.Start();
        }

        private static void InputManager()
        {
            while (true)
            {
                string input = Console.ReadLine();
                string[] args = input.Split(' ');
                string cmd = args[0];

                switch (cmd.ToLower())
                {
                    case "/connect":

                        if ((args.Length == 3) && ((args[1].Length > 0) && (args[2].Length > 0)))
                        {
                            string ip = args[1];
                            int port = int.Parse(args[2]);
                            Client = new ClientManager(ip, port);
                            Client.Connect();
                            Client.OnReceiveData += Client_OnReceiveData;
                        }
                        else
                        {
                            string ip = GetPublicIpAddress();
                            int port = 7777;
                            Console.WriteLine("CLIENT: Fetching public address.");
                            Client = new ClientManager(ip, port);
                            Client.Connect();
                            Client.OnReceiveData += Client_OnReceiveData;
                        }

                        break;

                    case "/createplayer":

                        if (Players > 0)
                        {
                            if ((args.Length == 4) && ((args[1].Length > 0) && (args[2].Length > 0) && (args[3].Length > 0)))
                            {
                                string name = args[1];
                                int health = int.Parse(args[2]);
                                int lives = int.Parse(args[3]);
                                Character = new Player(name, health, lives);
                                PktWriter = new PacketWriter();
                                PktWriter.Write((ushort)Headers.PlayerData);
                                PktWriter.WriteObject(Character);
                                Client.SendDataToServer(PktWriter.GetBytes());
                            }
                        }
                        else
                        {
                            Console.WriteLine("ERROR: Wait for other players.");
                        }

                        break;

                    case "/startgame":

                        if ((Character != null) && (Opponents.Count > 0))
                        {
                            PktWriter = new PacketWriter();
                            PktWriter.Write((ushort)Headers.GameStarted);
                            PktWriter.Write(1);
                            Client.SendDataToServer(PktWriter.GetBytes());
                        }
                        else
                        {
                            Console.WriteLine("ERROR: Please wait for the other player to create their character.");
                        }

                        break;

                    case "/disconnect":

                        Client.Disconnect();
                        break;

                    case "/exit":

                        Client.Disconnect();
                        return;

                    default:

                        if ((Client != null) && (Client.Connected == true))
                        {
                            Client.SendMessageToServer(input);
                        }
                        break;
                }
            }
        }

        private static void Client_OnReceiveData(byte[] data)
        {
            PktReader = new PacketReader(data);
            Headers headers = (Headers)PktReader.ReadUInt16();
            int playerid;

            switch (headers)
            {
                case Headers.Text:

                    string text = PktReader.ReadString();
                    Console.WriteLine("SERVER: " + text);
                    break;

                case Headers.PlayerData:

                    Player character = PktReader.ReadOjbect<Player>();
                    Opponents.Add(character);
                    Console.WriteLine("Player Name: " + character.Name);
                    Console.WriteLine("Player Health: " + character.Health);
                    Console.WriteLine("Player Lives: " + character.Lives);
                    break;

                case Headers.PlayerJoin:

                    int players = PktReader.ReadInt32();
                    playerid = PktReader.ReadInt32();
                    Console.WriteLine("A player joined on ID " + playerid.ToString());
                    Players = players;
                    break;

                case Headers.GameStarted:

                    playerid = PktReader.ReadInt32();
                    Console.WriteLine("The game has been started by player ID " + playerid.ToString());
                    break;
            }
        }

        private static string GetPublicIpAddress()
        {
            var request = (HttpWebRequest)WebRequest.Create("http://ifconfig.me");

            request.UserAgent = "curl"; // this simulate curl linux command

            string publicIPAddress;

            request.Method = "GET";
            using (WebResponse response = request.GetResponse())
            {
                using (var reader = new StreamReader(response.GetResponseStream()))
                {
                    publicIPAddress = reader.ReadToEnd();
                }
            }

            return publicIPAddress.Replace("\n", "");
        }
    }
}
